package com.yf.course.modules.course.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yf.ability.redis.service.RedisService;
import com.yf.base.api.api.dto.PagingReqDTO;
import com.yf.base.enums.CacheKey;
import com.yf.course.enums.CourseState;
import com.yf.course.modules.course.dto.CourseFileLearnDTO;
import com.yf.course.modules.course.dto.ext.CourseLearnResultExtDTO;
import com.yf.course.modules.course.dto.response.CourseFileLearnRespDTO;
import com.yf.course.modules.course.entity.*;
import com.yf.course.modules.course.mapper.CourseFileLearnMapper;
import com.yf.course.modules.course.service.*;

import com.yf.system.modules.log.service.SysLogLearnService;
import com.yf.system.modules.points.service.UserPointsService;
import com.yf.system.modules.user.UserUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

/**
* <p>
* 课件学习业务实现类
* </p>
*
* @author 聪明笨狗
* @since 2020-12-17 11:28
*/
@Service
public class CourseFileLearnServiceImpl extends ServiceImpl<CourseFileLearnMapper, CourseFileLearn> implements CourseFileLearnService {

    @Autowired
    private CourseLearnService courseLearnService;

    @Autowired
    private CourseService courseService;

    @Autowired
    private CourseFileService courseFileService;

    @Autowired
    private UserPointsService userPointsService;

    @Autowired
    private CourseRefFileService courseRefFileService;

    @Autowired
    private SysLogLearnService sysLogLearnService;
    @Autowired
    private CourseLearnDailyService courseLearnDailyService;

    @Autowired
    private CourseFileUnlockService courseFileUnlockService;

    @Autowired
    private RedisService redisService;


    @Override
    public IPage<CourseFileLearnRespDTO> paging(PagingReqDTO<CourseFileLearnDTO> reqDTO) {

        // 请求参数
        CourseFileLearnDTO params = reqDTO.getParams();

        if(params == null){
            params = new CourseFileLearnDTO();
        }

        // 查当前用户课件学习情况
        if(StringUtils.isEmpty(params.getUserId())){
            // 直接注入用户ID
            params.setUserId(UserUtils.getUserId(true));
        }


        return baseMapper.paging(reqDTO.toPage(), params);
     }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void start(String fileId) {

        QueryWrapper<CourseFileLearn> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(CourseFileLearn::getFileId, fileId)
                .eq(CourseFileLearn::getUserId, UserUtils.getUserId());

        CourseFileLearn learn = this.getOne(wrapper, false);

        if(learn==null){
            learn = new CourseFileLearn();
            learn.setFileId(fileId);
            learn.setUserId(UserUtils.getUserId());
            learn.setLearnSec(0L);
            this.save(learn);
        }

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public CourseLearnResultExtDTO incr(String userId, String courseId, String fileId, Long sec) {

        CourseLearnResultExtDTO respDTO = new CourseLearnResultExtDTO();
        respDTO.setAll(false);
        respDTO.setCurrent(false);
        respDTO.setLearnSec(0L);

        // 获取课程信息
        Course course = courseService.findSimple(courseId);

        // 不能学习了
        int canState = courseService.canLearn(course, userId);
        if(canState!=0){
            respDTO.setStopped(true);
            if(CourseState.OVER_TIME == canState){
                respDTO.setStopMsg("当前课程已超出每日学习时间上限！");
            }
            else if(CourseState.NOT_IN_TIME == canState){
                respDTO.setStopMsg("当前时间已不在可学习范围！");
            }
            else if(CourseState.PREPARE == canState){
                respDTO.setStopMsg("课程学习未开始！");
            }
            else if(CourseState.ENDED == canState){
                respDTO.setStopMsg("课程学习已结束！");
            }
            else if(CourseState.NOT_IN_PERSON == canState){
                respDTO.setStopMsg("您不在可学习成员名单里面，请确认！");
            }
            else if(CourseState.NOT_IN_DEPART == canState){
                respDTO.setStopMsg("您不在可学习部门名单里面，请确认！");
            }
            else{
                respDTO.setStopMsg("当前课程不可学习，请联系管理员！");
            }

            return respDTO;
        }


        QueryWrapper<CourseFileLearn> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(CourseFileLearn::getCourseId, courseId)
                .eq(CourseFileLearn::getFileId, fileId)
                .eq(CourseFileLearn::getUserId, userId);

        CourseFileLearn learn = this.getOne(wrapper, false);

        // 课件
        CourseRefFile fileRef = courseRefFileService.findOne(courseId, fileId);

        if(learn==null){
            learn = new CourseFileLearn();
            learn.setCourseId(courseId);
            learn.setFileId(fileId);
            learn.setUserId(userId);
            learn.setLearnSec(sec);
            learn.setFinished(false);
            learn.setUpdateTime(new Date());
            this.save(learn);
        }else {

            // 增加学习时长
            learn.setLearnSec(learn.getLearnSec() + sec);
            learn.setUpdateTime(new Date());

            // 当前课程学完标志
            if (learn.getLearnSec() >= fileRef.getNeedLearn()) {

                // 课件加积分
                if (fileRef.getPoints() > 0) {
                    CourseFile file = courseFileService.getById(fileRef.getFileId());
                    userPointsService.incr(userId, fileRef.getPoints(), "学完课件：" + file.getTitle(), learn.getId());
                }

                // 顺序阅读解锁
                if (course.getStepLock() != null && course.getStepLock()) {
                    // 解锁下一个
                    String nextId = courseFileUnlockService.unlockFile(userId, courseId, fileRef.getSort());
                    if (StringUtils.isNotBlank(nextId)) {
                        respDTO.setUnlockFile(nextId);
                        // 写入缓存
                        redisService.set(CacheKey.unlockKey(userId, courseId), nextId);
                    }
                }

                // 完成标识
                learn.setFinished(true);
            }

            // 更新状态
            this.updateById(learn);
        }

        // 保存日志
        sysLogLearnService.merge(userId, courseId, fileId, sec);

        // 保存当日学习
        courseLearnDailyService.incr(courseId, fileId, userId, sec);

        // 当前课件是否已学完
        respDTO.setLearnSec(learn.getLearnSec());
        respDTO.setLeftSec(fileRef.getNeedLearn() - learn.getLearnSec());
        respDTO.setCurrent(learn.getFinished()!=null && learn.getFinished());

        // 课程全部学完
        this.checkProcess(respDTO, learn.getCourseId(), userId);

        return respDTO;

    }

    @Override
    public void deleteByFile(List<String> ids) {
        QueryWrapper<CourseFileLearn> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .in(CourseFileLearn::getFileId, ids);
        this.remove(wrapper);
    }

    @Override
    public CourseFileLearn findOne(String userId, String courseId, String fileId) {
        QueryWrapper<CourseFileLearn> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(CourseFileLearn::getCourseId, courseId)
                .eq(CourseFileLearn::getUserId, userId)
                .eq(CourseFileLearn::getFileId, fileId);
        CourseFileLearn record = this.getOne(wrapper, false);
        if(record == null){
            record = new CourseFileLearn();
            record.setLearnSec(0L);
        }
        return record;
    }

    /**
     * 校验整个课程的学习进度
     * @param courseId
     */
    private void checkProcess(CourseLearnResultExtDTO respDTO, String courseId, String userId){


        // 已学完的数量
        int finish = baseMapper.countFinished(userId, courseId);
        int total = courseRefFileService.countByCourse(courseId);
        int state = finish >= total?1:0;

        QueryWrapper<CourseLearn> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(CourseLearn::getCourseId, courseId)
                .eq(CourseLearn::getUserId, userId);

        CourseLearn learn = courseLearnService.getOne(wrapper, false);
        if(learn == null){
            learn = new CourseLearn();
        }

        learn.setCourseId(courseId);
        learn.setUserId(userId);
        learn.setUpdateTime(new Date());

        learn.setLearnFile(finish);
        learn.setTotalFile(total);
        learn.setState(state);

        // 已学完
        if(1 == state){

            // 学完时间
            learn.setFinishTime(new Date());

            Course course = courseService.getById(courseId);
            if(course.getPoints()!=null && course.getPoints()>0){
                userPointsService.incr(userId, course.getPoints(), "学完课程："+course.getTitle(), courseId);
            }

            // 课程学完
            respDTO.setAll(true);
        }

        courseLearnService.saveOrUpdate(learn);
    }


}
